package cn.flying.cloud.core.interceptor;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;

import java.io.IOException;
import java.util.Enumeration;
import java.util.List;
import java.util.Map;
import java.util.Optional;
import java.util.concurrent.atomic.AtomicInteger;

import org.springframework.cloud.client.ServiceInstance;
import org.springframework.cloud.client.discovery.DiscoveryClient;
import org.springframework.http.HttpEntity;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpMethod;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.stereotype.Component;
import org.springframework.util.AntPathMatcher;
import org.springframework.util.StreamUtils;
import org.springframework.web.client.RestTemplate;

import cn.flying.cloud.base.core.interceptor.AbstractRequestInterceptor;
import cn.flying.cloud.core.properties.UriForwardRouteRule;

/**
 * uri转发处理
 *
 * @author: admin
 * @date: 2025年09月24日 09:38
 * @version: 1.0
 */
@Component
public class UriForwardingInterceptor extends AbstractRequestInterceptor {

    private final AntPathMatcher pathMatcher = new AntPathMatcher();
    private AtomicInteger atomicCount = new AtomicInteger(0);

    @Resource
    private UriForwardRouteRule uriForwardRouteRule;
    @Resource
    private DiscoveryClient discoveryClient;
    @Resource
    private RestTemplate restTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestUri = request.getRequestURI();
        String method = request.getMethod();

        // 查找匹配的转发规则
        Optional<Map.Entry<String, String>> matchedRule = uriForwardRouteRule.getRoutes().entrySet().stream()
                .filter(entry -> pathMatcher.match(entry.getKey(), requestUri))
                .findFirst();

        if (matchedRule.isPresent()) {
            // 找到匹配规则，执行转发
            String serviceName = matchedRule.get().getValue();
            forwardRequest(request, response, serviceName, requestUri, method);
            return false; // 不再执行后续的controller
        }

        // 没有匹配的规则，继续执行原有的controller逻辑
        return true;
    }

    private void forwardRequest(HttpServletRequest request, HttpServletResponse response, String serviceName, String requestUri, String method) throws IOException {
        // 从注册中心获取服务实例
        List<ServiceInstance> instances = discoveryClient.getInstances(serviceName);
        if (instances == null || instances.isEmpty()) {
            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "服务 " + serviceName + " 不可用");
            return;
        }

        // 找到第一个斜杠的位置
        int firstSlashIndex = requestUri.indexOf('/');

        // 从第一个斜杠之后开始找第二个斜杠
        int secondSlashIndex = requestUri.indexOf('/', firstSlashIndex + 1);

        // 如果找不到第二个斜杠，返回整个字符串
        if (secondSlashIndex == -1) {
            response.sendError(HttpServletResponse.SC_SERVICE_UNAVAILABLE, "服务 " + serviceName + " 不可用");
            return;
        }

        // 保留第二个斜杠及之后的部分
        String forwardUri = requestUri.substring(secondSlashIndex);

        // 简单起见，这里取第一个实例，实际应用中应该实现负载均衡策略
        int index = atomicCount.incrementAndGet() % instances.size();// 0+1
        ServiceInstance instance = instances.get(index);
        String baseUrl = instance.getUri().toString() + forwardUri;

        // 构建完整URL
        String targetUrl = buildTargetUrl(baseUrl, request);

        // 根据请求方法处理
        try {
            if (HttpMethod.GET.matches(request.getMethod())) {
                handleGet(request, response, targetUrl);
            } else if (HttpMethod.POST.matches(request.getMethod())) {
                handlePost(request, response, targetUrl);
            } else {
                // 其他方法...
            }
        } catch (Exception e) {
            response.sendError(HttpServletResponse.SC_INTERNAL_SERVER_ERROR, "转发请求到 " + serviceName + " 失败: " + e.getMessage());
        }
    }

    private String buildTargetUrl(String baseUrl, HttpServletRequest request) {
        StringBuilder url = new StringBuilder(baseUrl);

        String query = request.getQueryString();
        if (query != null && !query.isEmpty()) {
            url.append("?").append(query);
        }
        return url.toString();
    }

    private void handleGet(HttpServletRequest request, HttpServletResponse response, String targetUrl) throws IOException {
        ResponseEntity<byte[]> resp = restTemplate.exchange(targetUrl, HttpMethod.GET, null, byte[].class);

        copyResponse(resp, response);
    }

    private void handlePost(HttpServletRequest request, HttpServletResponse response, String targetUrl) throws IOException {
        byte[] body = StreamUtils.copyToByteArray(request.getInputStream());
        HttpHeaders headers = new HttpHeaders();
        // 复制请求头
        Enumeration<String> headerNames = request.getHeaderNames();
        // 构建请求头
        headers.add(HttpHeaders.ACCEPT, MediaType.APPLICATION_JSON_VALUE);
        // 遍历并复制每个头信息
        while (headerNames.hasMoreElements()) {
            String headerName = headerNames.nextElement();

            // 获取指定头名称的所有值
            Enumeration<String> headerValues = request.getHeaders(headerName);

            // 将所有值添加到目标HttpHeaders中
            while (headerValues.hasMoreElements()) {
                String headerValue = headerValues.nextElement();
                headers.add(headerName, headerValue);
            }
        }

        HttpEntity<byte[]> entity = new HttpEntity<>(body, headers);
        ResponseEntity<byte[]> resp = restTemplate.exchange(targetUrl, HttpMethod.POST, entity, byte[].class);

        copyResponse(resp, response);
    }

    private void copyResponse(ResponseEntity<byte[]> source, HttpServletResponse target) throws IOException {
        // 复制响应状态、头信息和响应体
        target.setStatus(source.getStatusCodeValue());
        source.getHeaders().forEach((name, values) ->
                values.forEach(value -> target.addHeader(name, value)));
        if (source.getBody() != null) {
            target.getOutputStream().write(source.getBody());
        }
    }

    /**
     * 设置拦截器的执行顺序，返回值越小优先级越高
     *
     * @return
     */
    @Override
    public Integer getOrder() {
        return Integer.MIN_VALUE + 100;
    }
}
